#include "include/VectorTest.h"
#include "include/App.h"
#include "include/Scripting.h"

#include "include/NetManager.h"
#include "include/NetworkInterface.h"
#include "include/NetworkMethods.h"


using namespace Ei;
using namespace Ogre;

/** Constructor. Sets up the OSC root address space and allocates an UDP receive buffer
 */
NetManager::NetManager()
{
	// setup private members
        mLocalPort = App::scripting()->getTableInt("net", "localport");
        mRemotePort = App::scripting()->getTableInt("net", "remoteport");
        remote_ip = App::scripting()->getTableCString("net", "broadcastIP");
        maxMethods = App::scripting()->getTableInt("net", "maxMethods");
        numMethods = 0;
        //setup the interface
   	mNetworkInterface = new NetworkInterface;
   	mNetworkInterface->NetworkInit(mLocalPort);
   	      	
   	// setup the root container
	WOscContainerInfo rootInfo("root");	
	mRootContainer = new WOscContainer(&rootInfo, maxMethods);
	mNetworkInterface->SetAddressSpace(mRootContainer);
	
	// Setup local IP	
	char ac[80];
    	if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR) 
	    {
       		eilog("Error getting Hostname ");
        	return ;
   	     }
    	eilog("Host name is " + String(ac));
    	struct hostent *phe = gethostbyname(ac);
    	
    	if (phe == 0) 
	  {
         	eilog( "Could not find any IP for : " );
        	return ;
    	  }	

    	for (int i = 0; phe->h_addr_list[i] != 0; ++i) 
	{
          memcpy(&local_ip, phe->h_addr_list[i], sizeof(struct in_addr));
          eilog("Address : " +  String(inet_ntoa(local_ip)));
    	}
  
	eilog("Net manager managing:") ;	
}
 
/** Destructor. Removes the address space and deallocates the UDP receive
 * buffer.
 */
NetManager::~NetManager()
{
	mNetworkInterface->NetworkHalt();
	delete mNetworkInterface;
	eilog("Net manager shut down:");
}

//
// setup methods

void NetManager::SetupMethods()
{
	this->AddNetworkMethod("/sios/sensors/accmag/acc/data", &NetworkEvents::GetAccData);
	this->AddNetworkMethod("/sios/sensors/accmag/mag/data", &NetworkEvents::GetMagData);
	this->AddNetworkMethod("/tracking/hx11", &NetworkEvents::getHexamiteData);
	
	this->AddNetworkMethod("/position/all", &NetworkEvents::setNodePosition);
	this->AddNetworkMethod("/orientation/all", &NetworkEvents::setNodeOrientation);


}


// Add Network Method
void NetManager::AddNetworkMethod(String adress, void (NetworkEvents::*methodUsed)(const WOscMessage *))
{

	if (numMethods >= maxMethods)
	{
	  eilog("maximum number of methods defined");
	  return;
	}
	
	// check if methods exists
	// get the full Adress space that is already available
	// and create a list of all defined adress spaces 
	// and methods	
	if (numMethods)
	{
		String UnsplitAdressSpace = (String(mRootContainer->GetAddressSpace().GetBuffer()));
		std::vector<String> curAdressSpace = StringUtil::split(UnsplitAdressSpace);
		std::vector<String>::iterator it;
			
     		for(it=curAdressSpace.begin(); it!=curAdressSpace.end(); ++it)
    	 	{      
			if (adress.compare(*it) == 0)
			{
	      	 	eilog("Method " +  adress + " already defined");
	      	 	return;
			}
     	 	}		
	}
	//
	// Create the new method secified in the 
	//	

	// split new adress in Adress parts and method
	String newMethod = adress.substr(adress.find_last_of("/")+ 1);
	String newAdress = adress.substr(0,adress.find_last_of("/")+ 1);
	std::vector<String> NewAdressParts = StringUtil::split(newAdress, "/");
	std::vector<String>::iterator it;
		  		
	WOscContainer* TempContainer = mRootContainer;
	WOscContainerInfo* TempContainerInfo = NULL;
	
	WOscString _woscAdress;
	WOscString _woscMethod;
 	// create the new adress and method,
	for(it=NewAdressParts.begin(); it!=NewAdressParts.end(); ++it)
    	 {      
		_woscAdress = (*it).c_str();
		TempContainerInfo = new WOscContainerInfo(_woscAdress.GetBuffer());
		TempContainer = new WOscContainer(TempContainerInfo, 
						  TempContainer,
						  const_cast<char*>(_woscAdress.GetBuffer()));
		
     	 }
     	 // creating the event
     	_woscMethod= newMethod.c_str();
     	 new NetworkMethod( TempContainer, 
	      		    mNetworkInterface, 
			    const_cast<char*>(_woscMethod.GetBuffer()), 
			    methodUsed);
	
	eilog("Created Method : " + newAdress + newMethod);					    
	numMethods++;
}


void NetManager::pollSocket(Real dt)
{
    //does: Checks and processes all messages waiting.	
    mNetworkInterface->CheckForPackets();
}


void NetManager::sendMessage(String message, bool parseInt)
{	
    // parse string in adress and variables
    // parse parameters
    String params[100];
    int nParams = 0;
    String adress ;
    String para; 
    
    if(message.find(" ") != String::npos)
    {
	adress = message.substr(0,message.find_first_of(" "));
        para = message.substr(message.find_first_of(" ")); 
    }
    else
    {
	adress = message;
	para = " ";		
    }
    
    if (!(adress[0] == '/'))
    {// check if Adress starts with a slash
	eilog("Message doesn't start with a slash");
	return;		
    }
    	
    while (  ( (nParams <= 100) && (!(para.empty())) )  )
    {
    	// add parameter to list 
    	params[nParams] = para.substr(para.find_last_of(" ") + 1);
    	para.erase(para.find_last_of(" "));		
    	if (!(params[nParams].empty()))
    	{// do not add an empty string to parameters
	  nParams++;
	}	
   }
		
   // assemble message
   WOscMessage msg(adress.c_str());
 	    
   // add parameters all parameteres
   if(nParams){
    for ( int i = (nParams -1); i >= 0; i-- )
    {	
	// check if param is a String or a Number
	bool isString = false;	
	for (unsigned int j = 1; j < params[i].length(); j++)	
	{
	 	char c =  params[i][j];
	 	if(!(std::isdigit((int) c) || c == '.' || c == 'e' || c == '-' || c == 'E')) 
	 	{	
			  isString = true;
			  break;	
	 	}		
        }
	
	// add string, Float or Int to message
	if (isString)
	{
		msg.Add(params[i].c_str());
		eilog("added str " + String(params[i]));			
	}
	else
   	{
	 	if ((params[i].find(".") != std::string::npos) || parseInt == false)
	  	{
		msg.Add((float)atof(params[i].c_str()) );
		eilog("added Float " + String(params[i]));
	   	}
	 	else
	 	{
  	 	msg.Add((int)atoi(params[i].c_str()) );
	 	eilog("added Int " + String(params[i]));		
	  	} 
	}
      }	
     }// end add all parmeters for-loop
   eilog("sending msg");
   send(msg);
   eilog("msg send");

}


void NetManager::send(WOscMessage& msg)
{
	
	TheNetReturnAddress ra;
	ra.m_addr.sin_family         = AF_INET;
	ra.m_addr.sin_addr.s_addr    = inet_addr(remote_ip.c_str());
	ra.m_addr.sin_port           = htons(mRemotePort);
	mNetworkInterface->NetworkSend(msg.GetBuffer(), msg.GetBufferLen(), &ra);
}



